<template>
  <!-- antv x6图形引擎 -->
  <div class="service-adaptation">
    <Header :header-name="$route.meta.title">

      <template v-slot:end>
        <div style="height: 32px">
          <el-button-group v-if="sceneId">
            <el-button v-permission="['SERVICEADAPTATION_SAVE']" size="small" :disabled="loading" :loading="loading" @click="saveBtn"> 保存 </el-button>
            <el-button v-permission="['SERVICEADAPTATION_SAVE']" size="small" :disabled="loading" :loading="loading" @click="connectivityTestBtn"> 连通测试 </el-button>
            <el-button v-permission="['SERVICEADAPTATION_CONNECTIVITYTEST']" size="small" :disabled="loading" :loading="loading" @click="executingBtn"> {{ startFlagList[startFlag] }} </el-button>
            <el-button size="small" :disabled="loading" :loading="loading" @click="lookLogs"> 查看日志 </el-button>
          </el-button-group>
        </div>
      </template>
    </Header>

    <el-row :gutter="10" class="service-adaptation-body">
      <!-- 分类管理/新建管理 -->
      <el-col id="left-col" :span="4" class="left-col">
        <div class="service-adaptation-body-left">
          <el-button v-permission="['SERVICEADAPTATION_ADD_CLASSIFY']" size="small" @click="addClassifyBtn"> 新建场景分类</el-button>
          <el-button v-permission="['SERVICEADAPTATION_ADD_ADAPTATION']" size="small" @click="addAdaptationBtn"> 新建场景</el-button>

          <el-tree
            ref="tree"
            v-loading="treeLoading"
            :data="treeData"
            :props="defaultProps"
            default-expand-all
            :highlight-current="true"
            :expand-on-click-node="false"
            @node-click="handleNodeClick"
          >
            <p slot-scope="{ node, data }" class="custom-tree-node">
              <span :title="node.label">
                <i v-if="data.isScene === 'N'" class="el-icon-folder" />
                {{ node.label }}
              </span>
              <span class="tree-btn">
                <el-button v-permission="['SERVICEADAPTATION_UPDATE']" type="text" icon="el-icon-edit-outline" @click="updateBtn(data, node)" />
                <el-button v-permission="['SERVICEADAPTATION_DEL']" type="text" icon="el-icon-delete" class="text-del-btn" @click="delClassifyBtn(data)" />
              </span>
            </p>
          </el-tree>
        </div>
        <!-- 中间拖动栏 -->
        <div id="resize" class="resize" title="收缩侧边栏">⋮</div>
      </el-col>
      <el-col id="right-col" :span="20" class="right-col">
        <!-- 流程图容器 -->
        <div id="container" :class="{ 'is-disable': !requestSystemId }" />
      </el-col>
    </el-row>

    <!-- 各节点表单操作 -->
    <el-drawer
      :visible.sync="drawerVisible"
      :destroy-on-close="true"
      :wrapper-closable="false"
      :size="600"
    >
      <component :is="currentComponent" ref="nodeComponent" :data-mapping="dataMapping" :provider-has-select="providerHasSelect" :node-type="nodeType" :title="titleInfo" :request-system-id="requestSystemId" @nodeForm="updateNodeForm" />
    </el-drawer>

    <!-- 查看日志弹框 -->
    <el-dialog
      custom-class="logs-dialog"
      title="日志"
      :visible.sync="logsDialogVisible"
      :destroy-on-close="true"
      width="1000px"
    >
      <SceneLogs :scene-id="sceneId" />
      <span slot="footer" class="dialog-footer">
        <el-button @click="logsDialogVisible = false">关 闭</el-button>
      </span>
    </el-dialog>

    <!-- 新增/编辑场景分类 -->
    <el-dialog
      title="新增/编辑场景分类"
      :visible.sync="classifyDialogVisible"
      width="600px"
    >
      <el-form ref="classifyForm" :rules="classifyFormRules" :model="classifyForm" label-width="100px">
        <el-form-item label="系统名称:" prop="requestSystemId">
          <el-select v-model="classifyForm.systemId" clearable placeholder="请选择系统名称" @change="systemIdChange">
            <el-option
              v-for="(item, index) in systemIdList"
              :key="index"
              :label="item.systemName"
              :value="item.id"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="上级分类:" prop="parentIdPath">
          <el-cascader
            v-model="classifyForm.parentIdPath"
            :disabled="!classifyForm.systemId"
            clearable
            :options="parentTreeData"
            :props="{ checkStrictly: true, value: 'id', label: 'classifyName' }"
          />
        </el-form-item>
        <el-form-item label="分类名称:" prop="classifyName">
          <el-input v-model.trim="classifyForm.classifyName" clearable :maxlength="50" placeholder="请输入分类名称" />
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="classifyDialogVisible = false">取 消</el-button>
        <el-button type="primary" :loading="!canClick" :disabled="!canClick" @click="classifyConfirm('classifyForm')">确 定</el-button>
      </span>
    </el-dialog>

    <!-- 场景配置 -->
    <ScenarioConfiguration ref="scenarioConfiguration" :classify-tree="treeDataOnlyClassify" @refresh="classifyGetTree" />
  </div>
</template>

<script>
import { Graph, Shape } from '@antv/x6'
import { Stencil } from '@antv/x6-plugin-stencil'
import { Transform } from '@antv/x6-plugin-transform'
import { Selection } from '@antv/x6-plugin-selection'
import { Snapline } from '@antv/x6-plugin-snapline'
import { Keyboard } from '@antv/x6-plugin-keyboard'
import { Clipboard } from '@antv/x6-plugin-clipboard'
import { History } from '@antv/x6-plugin-history'
import {
  addApi,
  classifyAddApi,
  classifyDeleteApi,
  classifyGetTreeApi,
  getDetailApi,
  onlyClassifyGetTreeApi,
  getTreeOnlyClassifyBySystemIdApi,
  sceneDeleteApi,
  sceneGetDetailApi,
  connectivityTestApi,
  executingApi
} from '@/api/serviceManage/serviceAdaptation'
import { getSystemListApi } from '@/api/serviceManage/requestPartyServiceManage'
import _ from 'lodash'
import { uuId } from '@/framework/utils/uuid'

// 场景配置
import ScenarioConfiguration from './components/ScenarioConfiguration'
// 提供方/请求方服务
import ProviderNodeForm from './components/ProviderNodeForm'
// 队列配置
import QueueConfigNodeForm from './components/QueueConfigNodeForm'
// 数据映射
import DataMappingNodeForm from './components/DataMappingNodeForm'
// 场景日志
import SceneLogs from './components/SceneLogs'

export default {
  name: 'ServiceAdaptation',

  components: {
    ScenarioConfiguration,
    ProviderNodeForm,
    QueueConfigNodeForm,
    DataMappingNodeForm,
    SceneLogs
  },

  data () {
    return {
      // 流程图是否可编辑
      graphContainerDisabled: false,
      currentComponent: ProviderNodeForm,
      defaultProps: {
        children: 'children',
        label: 'classifyName'
      },
      treeLoading: false,
      treeData: [],
      treeDataOnlyClassify: [],
      parentTreeData: [],
      loading: false,
      form: {
        id: ''
      },
      rules: {
        labelName: [
          { required: true, message: '请输入节点名称', trigger: 'blur' }
        ]
      },
      drawerVisible: false,
      graph: null,
      cell: null,
      edge: null,
      graphData: '[]',
      cellData: {},

      classifyDialogVisible: false,
      classifyFormRules: {
        systemId: { required: true, message: '请选择系统名称', trigger: 'change' },
        classifyName: { required: true, message: '请输入分类名称', trigger: 'blur' },
        parentIdPath: { required: true, message: '请选择上级分类', trigger: 'change' }
      },
      classifyForm: {
        systemId: '',
        classifyName: '',
        parentIdPath: []
      },
      canClick: true,

      // 场景id
      sceneId: '',
      // 请求方系统id
      requestSystemId: '',
      // 各表单表头
      titleInfo: '',
      // 节点分类属性
      nodeType: '',
      dataMapping: {
        providerList: [],
        supplicantList: []
      },
      // 记录提供方服务已经选择的服务
      providerHasSelect: [],
      // 日志tab
      activeName: '',
      // 场景启动/停止状态
      startFlag: '1',
      startFlagList: ['', '启动', '停止'],
      // 日志弹框
      logsDialogVisible: false,
      // 系统列表
      systemIdList: []
    }
  },

  mounted () {
    this.classifyGetTree()

    // 初始化图形
    this.preWork()

    this.graph.on('cell:dblclick', ({ e, x, y, cell, view }) => {
      if (cell.isNode()) {
        // start 开始
        // providerServices 提供方
        // dataMapping 数据映射
        // queueConfig 队列配置
        // supplicantServices 请求方服务
        // end 结束
        const nodeComponent = {
          providerServices: ProviderNodeForm,
          dataMapping: DataMappingNodeForm,
          queueConfig: QueueConfigNodeForm,
          supplicantServices: ProviderNodeForm
        }
        if (nodeComponent[cell.attrs.data.type]) {
          this.nodeType = cell.attrs.data.type

          /* 如果节点是数据映射，需判断是否存在提供方服务、请求方服务，
          且提供方服务、请求方服务已经配置好接口 */
          this.providerHasSelect = []
          if (this.nodeType === 'dataMapping') {
            const graphData = this.graph.toJSON().cells
            this.dataMapping.providerList = []
            this.dataMapping.supplicantList = []
            graphData.forEach(ele => {
              if (ele.shape !== 'edge') {
                if (ele.attrs.data.data && ele.attrs.data.data.componentId) {
                  if (ele.attrs.data.type === 'providerServices') {
                    this.dataMapping.providerList.push({
                      id: ele.attrs.data.data.componentId,
                      name: ele.attrs.data.data.componentName
                    })
                  } else if (ele.attrs.data.type === 'supplicantServices') {
                    this.dataMapping.supplicantList.push({
                      id: ele.attrs.data.data.componentId,
                      name: ele.attrs.data.data.componentName
                    })
                  }
                }
              }
            })
            if (this.dataMapping.providerList.length === 0 || this.dataMapping.supplicantList.length === 0) {
              return this.$message.warning('流程中应存在提供方服务和请求方服务， 且都已绑定接口！')
            }
          } else if (this.nodeType === 'providerServices') {
            const providerHasSelect = []
            this.graph.toJSON().cells.forEach(ele => {
              if (ele.shape !== 'edge' && ele.attrs.data.type === 'providerServices') {
                if (ele.attrs.data.data &&
                  ele.attrs.data.data.componentId &&
                  ele.attrs.data.data.componentId !== cell.attrs.data.data.componentId) {
                  providerHasSelect.push(ele.attrs.data.data.componentId)
                }
              }
            })

            this.providerHasSelect = providerHasSelect
          }

          this.cell = cell
          this.drawerVisible = true
          this.currentComponent = nodeComponent[cell.attrs.data.type]
          this.titleInfo = cell.attrs.text.text
          this.$nextTick(() => {
            const attr = cell.attrs
            this.$refs.nodeComponent.initForm(_.cloneDeep(attr.data.data))
          })
        }
      }
    })
    if (this.$route.query.id) {
      this.getDetail()
    }

    this.dragControllerDiv()
  },

  methods: {
    dragControllerDiv() {
      const left = document.getElementById('left-col')
      const line = document.getElementById('resize')
      const right = document.getElementById('right-col')
      // 鼠标按下事件
      line.onmousedown = function (e) {
        const startX = e.clientX
        line.left = line.offsetLeft
        // 鼠标拖动事件
        document.onmousemove = function (e) {
          const moveLen = line.left + (e.clientX - startX)
          if (
            moveLen >= document.body.clientWidth * 0.1 &&
            moveLen <= document.body.clientWidth * 0.4
          ) {
            // line.style.left = moveLen + 'px'
            left.style.width = moveLen + 'px'
            right.style.width = document.body.clientWidth - moveLen + 'px'
          }
        }
        document.onmouseup = function () {
          document.onmousemove = null
          document.onmouseup = null
        }
      }
    },

    // 系统名称change
    systemIdChange (val) {
      this.classifyForm.parentIdPath = ''
      this.getParentTreeData()
    },

    // 节点更新
    updateNodeForm (data) {
      this.drawerVisible = false
      if (data) {
        const params = this.cell.attrs.data
        params.data = data
        this.cell.updateAttrs({
          data: params
        })
      }
    },

    // 获取左侧树列表
    classifyGetTree (data, requestSystemId) {
      this.sceneId = data
      this.requestSystemId = requestSystemId
      this.treeLoading = true
      classifyGetTreeApi()
        .then(({ code, data }) => {
          if (code === '00000') {
            this.treeData = data
          }
        }).finally(() => {
          this.treeLoading = false
        })
      onlyClassifyGetTreeApi().then(({ code, data }) => {
        if (code === '00000') {
          this.treeDataOnlyClassify = data
        }
      })
      // 获取系统
      getSystemListApi()
        .then(({ code, data }) => {
          if (code === '00000') {
            this.systemIdList = data
          }
        })
    },

    // 点击树列表
    handleNodeClick (data) {
      // 如果是场景则获取场景详情
      if (data.isScene === 'Y') {
        this.sceneId = data.id
        this.requestSystemId = data.requestSystemId
        this.getDetail(data)
      } else {
        this.sceneId = ''
        this.requestSystemId = ''
        this.graph.fromJSON({})
      }
    },

    // 删除场景分类按钮
    delClassifyBtn (data) {
      this.$confirm('此操作将永久删除该数据, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        const api = data.isScene === 'N' ? classifyDeleteApi : sceneDeleteApi
        api({
          id: data.id
        }).then(({ code }) => {
          if (code === '00000') {
            this.$message.success('删除成功')
            this.graph.fromJSON({})
            this.classifyGetTree()
          }
        })
      })
    },

    // 新建场景分类按钮
    async addClassifyBtn () {
      this.classifyDialogVisible = true
      // this.getParentTreeData()
      await this.$nextTick()
      this.classifyForm = {
        systemId: '',
        classifyName: '',
        parentIdPath: []
      }
      this.$refs.classifyForm.clearValidate()
    },

    getParentTreeData () {
      getTreeOnlyClassifyBySystemIdApi({
        systemId: this.classifyForm.systemId
      }).then(({ code, data }) => {
        if (code === '00000') {
          this.parentTreeData = [
            {
              id: '-1',
              classifyName: '根节点',
              children: data
            }
          ]
        }
      })
    },

    // 修改按钮
    async updateBtn (data, node) {
      if (data.isScene === 'N') {
        this.classifyDialogVisible = true
        await this.$nextTick()
        this.classifyForm = {
          systemId: data.systemId,
          classifyName: data.classifyName,
          parentIdPath: data.parentIdPath.split(','),
          id: data.id
        }
        this.getParentTreeData()
      } else {
        this.$refs.scenarioConfiguration.getInitData(data)
      }
    },

    // 场景详情
    getDetail (data) {
      this.form.id = data.id
      // 获取初始化图形
      getDetailApi({
        sceneId: data.id
      }).then(({ code, data }) => {
        if (code === '00000') {
          console.log(data)
          if (data && data.length === 0) {
            data = [{
              position: {
                x: -580,
                y: -30
              },
              size: {
                width: 86,
                height: 46
              },
              attrs: {
                text: {
                  text: '开始'
                },
                body: {
                  rx: 6,
                  ry: 6
                },
                data: {
                  type: 'start'
                }
              },
              visible: true,
              shape: 'custom-rect-start',
              ports: {
                groups: {
                  right: {
                    position: 'right',
                    attrs: {
                      circle: {
                        r: 4,
                        magnet: true,
                        stroke: '#F8CA52',
                        strokeWidth: 1,
                        fill: '#fff',
                        style: {
                          visibility: 'hidden'
                        }
                      }
                    }
                  }
                },
                items: [
                  {
                    group: 'right',
                    id: uuId(36)
                  }
                ]
              },
              id: uuId(36),
              zIndex: 1
            }]
          }
          this.graph.fromJSON(data)
          this.graphData = JSON.stringify(this.graph.toJSON().cells)
          this.graph.centerContent()
        }
      })
      this.getSceneGetDetailApi()
    },

    // 获取其他详情
    getSceneGetDetailApi () {
      sceneGetDetailApi({
        id: this.form.id
      }).then(({ code, data }) => {
        if (code === '00000') {
          this.requestSystemId = data.requestSystemId
          this.startFlag = data.status
        }
      })
    },

    // 新建/修改场景分类确定按钮
    classifyConfirm (formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          this.canClick = false
          const parmas = {
            id: this.classifyForm.id || undefined,
            systemId: this.classifyForm.systemId,
            classifyName: this.classifyForm.classifyName,
            parentIdPath: this.classifyForm.parentIdPath.join(','),
            parentId: this.classifyForm.parentIdPath.length ? this.classifyForm.parentIdPath.at([-1]) : -1
          }
          classifyAddApi({
            ...parmas
          }, this.classifyForm.id).then(({ code, data }) => {
            if (code === '00000') {
              this.classifyGetTree()
              this.classifyDialogVisible = false
            }
          }).finally(() => {
            this.canClick = true
          })
        }
      })
    },

    // 新建场景按钮
    addAdaptationBtn () {
      this.$refs.scenarioConfiguration.getInitData()
    },

    // 初始化数据
    initData () {
      // fromJSON - 按照指定的 JSON 数据渲染节点和边
      this.graph.fromJSON(this.cellData)
    },

    // 获取所有数据并保存
    saveBtn () {
      /*  toJSON - 导出图中的节点和边，返回一个具有 { cells: [] } 结构的对象，
        其中 cells 数组按渲染顺序保存节点和边。 */
      // const cells = this.graph.toJSON().cells
      // const edgeList = []
      // const cellList = []
      // cells.forEach(element => {
      //   if (element.shape === 'edge') {
      //     edgeList.push(element)
      //   } else {
      //     cellList.push(element)
      //   }
      // })

      // if (cellList.length - edgeList.length !== 1) {
      //   return this.$message.warning('请完善组件配置')
      // }
      this.loading = true
      console.log(this.graph.toJSON().cells)
      addApi({
        cells: this.graph.toJSON().cells,
        id: this.form.id || undefined,
        sceneId: this.sceneId
      }, this.form.id).then(({ code, data }) => {
        if (code === '00000') {
          this.$message.success('保存成功')
          this.graphData = JSON.stringify(this.graph.toJSON().cells)
        }
      }).finally(() => {
        this.loading = false
      })
    },

    // 连通测试按钮
    connectivityTestBtn () {
      this.loading = true
      connectivityTestApi({
        cells: this.graph.toJSON().cells,
        id: this.form.id || undefined,
        sceneId: this.sceneId
      }).then(({ code, data }) => {
        if (code === '00000') {
          this.$message.success('连通测试成功')
        }
      }).finally(() => {
        this.loading = false
      })
    },

    // 启动/停止按钮
    executingBtn () {
      if (this.graphData !== JSON.stringify(this.graph.toJSON().cells)) {
        return this.$message.warning('组件配置发生变化，请先保存')
      }
      this.loading = true
      executingApi({
        sceneId: this.sceneId
      }, this.startFlag).then(({ code, data }) => {
        if (code === '00000') {
          this.$message.success(this.startFlagList[this.startFlag] + '成功')
          this.getSceneGetDetailApi()
        }
      }).finally(() => {
        this.loading = false
      })
    },

    // 查看日志按钮
    lookLogs () {
      this.logsDialogVisible = true
    },

    // 初始化
    preWork () {
      const container = document.getElementById('container')
      const stencilContainer = document.createElement('div')
      stencilContainer.id = 'stencil'
      const graphContainer = document.createElement('div')
      graphContainer.id = 'graph-container'
      container.appendChild(stencilContainer)
      container.appendChild(graphContainer)

      this.createTool()
    },

    // 创建工具
    createTool () {
      // #region 初始化画布
      this.graph = new Graph({
        container: document.getElementById('graph-container'),
        grid: true,
        panning: true,
        interacting: true,
        mousewheel: {
          enabled: true,
          zoomAtMousePosition: true,
          modifiers: 'ctrl',
          minScale: 0.5,
          maxScale: 3
        },
        connecting: {
          router: 'manhattan',
          connector: {
            name: 'rounded',
            args: {
              radius: 8
            }
          },
          anchor: 'center',
          connectionPoint: 'anchor',
          allowBlank: false,
          allowMulti: false,
          allowLoop: false,
          allowNode: false,
          highlight: true,
          snap: {
            radius: 20
          },
          createEdge() {
            return new Shape.Edge({
              attrs: {
                line: {
                  stroke: '#A7A7A7',
                  strokeWidth: 2,
                  targetMarker: {
                    name: 'block',
                    width: 12,
                    height: 8
                  }
                }
              },
              zIndex: 0
            })
          },
          validateConnection({
            sourceCell,
            targetCell,
            sourceMagnet,
            targetMagnet
          }) {
            // 不能连接自身
            if (sourceCell === targetCell) {
              return false
            }

            // 输出节点为右侧连接桩
            if (
              !sourceMagnet ||
              sourceMagnet.getAttribute('port-group') === 'left'
            ) {
              return false
            }
            // 输入节点为左侧连接桩
            if (
              !targetMagnet ||
              targetMagnet.getAttribute('port-group') !== 'left'
            ) {
              return false
            }

            // 一个输出只能连接一条线，开始、提供方服务可以多个。
            const edges = this.getEdges()
            const sourceCellId = sourceCell.id
            const targetCellId = targetCell.id
            if ((sourceCell.attrs.data.type === 'providerServices' || sourceCell.attrs.data.type === 'start') &&
                targetCell.attrs.data.type === 'providerServices') return true
            if (
              edges.find((edge) => {
                return (edge.getSourceCellId() === sourceCellId && edge.getTargetCellId()) ||
                      (edge.getTargetCellId() === targetCellId &&
                      (targetCell.attrs.data.type !== 'dataMapping' ||
                      sourceCell.attrs.data.type !== 'providerServices'))
              })
            ) {
              return false
            }

            return true
          }
        },
        highlighting: {
          magnetAvailable: {
            name: 'stroke',
            args: {
              padding: 3,
              attrs: {
                strokeWidth: 3,
                stroke: '#52c41a'
              }
            }
          },
          magnetAdsorbed: {
            name: 'stroke',
            args: {
              attrs: {
                fill: '#52c41a',
                stroke: '#52c41a'
              }
            }
          }
        }
      })

      // #region 使用插件
      this.graph
        .use(
          new Transform({
            resizing: true
            // rotating: true
          })
        )
        .use(
          new Selection({
            rubberband: false,
            showNodeSelectionBox: true
          })
        )
        .use(new Snapline())
        .use(new Keyboard())
        .use(new Clipboard())
        .use(new History())

      // #region 初始化 stencil
      const stencil = new Stencil({
        title: '组件配置',
        target: this.graph,
        stencilGraphWidth: 800,
        stencilGraphHeight: 80,
        collapsable: false,
        groups: [
          {
            title: '基础流程图',
            name: 'group'
          }
        ],
        layoutOptions: {
          columns: 8,
          columnWidth: 100,
          rowHeight: 55
        }
      })
      document.getElementById('stencil').appendChild(stencil.container)

      // #region 快捷键与事件
      this.graph.bindKey(['meta+c', 'ctrl+c'], () => {
        const cells = this.graph.getSelectedCells()
        if (cells.length) {
          this.graph.copy(cells)
        }
        return false
      })
      this.graph.bindKey(['meta+x', 'ctrl+x'], () => {
        const cells = this.graph.getSelectedCells()
        if (cells.length) {
          this.graph.cut(cells)
        }
        return false
      })
      this.graph.bindKey(['meta+v', 'ctrl+v'], () => {
        if (!this.graph.isClipboardEmpty()) {
          const cells = this.graph.paste({ offset: 32 })
          this.graph.cleanSelection()
          this.graph.select(cells)
        }
        return false
      })

      // undo redo
      this.graph.bindKey(['meta+z', 'ctrl+z'], () => {
        if (this.graph.canUndo()) {
          this.graph.undo()
        }
        return false
      })
      this.graph.bindKey(['meta+shift+z', 'ctrl+shift+z'], () => {
        if (this.graph.canRedo()) {
          this.graph.redo()
        }
        return false
      })

      // select all 选中全部
      // this.graph.bindKey(['meta+a', 'ctrl+a'], () => {
      //   const nodes = this.graph.getNodes()
      //   if (nodes) {
      //     this.graph.select(nodes)
      //   }
      // })

      // delete
      this.graph.bindKey('delete', () => {
        const cells = this.graph.getSelectedCells()
        if (cells.length) {
          this.graph.removeCells(cells)
        }
      })

      // zoom
      this.graph.bindKey(['ctrl+1', 'meta+1'], () => {
        const zoom = this.graph.zoom()
        if (zoom < 1.5) {
          this.graph.zoom(0.1)
        }
      })
      this.graph.bindKey(['ctrl+2', 'meta+2'], () => {
        const zoom = this.graph.zoom()
        if (zoom > 0.5) {
          this.graph.zoom(-0.1)
        }
      })

      // 控制连接桩显示/隐藏
      const showPorts = (ports, show) => {
        for (let i = 0, len = ports.length; i < len; i += 1) {
          ports[i].style.visibility = show ? 'visible' : 'hidden'
        }
      }
      this.graph.on('node:mouseenter', () => {
        const container = document.getElementById('graph-container')
        const ports = container.querySelectorAll(
          '.x6-port-body'
        )
        showPorts(ports, true)
      })

      // 点击选中连接线，并将上次选中的修改回原颜色
      this.graph.on('edge:click', ({ e, edge, view }) => {
        if (this.edge) {
          this.edge.attr({
            line: {
              strokeDasharray: 0,
              stroke: '#A7A7A7'
            }
          })
        }
        this.edge = edge
        this.edge.attr({
          line: {
            strokeDasharray: 5,
            stroke: '#239EDD'
          }
        })
      })

      // 点击画布空白，将上次选中的修改回原颜色
      this.graph.on('blank:click', ({ e }) => {
        if (this.edge) {
          this.edge.attr({
            line: {
              strokeDasharray: 0,
              stroke: '#A7A7A7'
            }
          })
        }
      })
      this.graph.on('node:mouseleave', () => {
        const container = document.getElementById('graph-container')
        const ports = container.querySelectorAll(
          '.x6-port-body'
        )
        showPorts(ports, false)
      })

      // #region 初始化图形
      const ports = (strokeColor) => {
        return {
          groups: {
            right: {
              position: 'right',
              attrs: {
                circle: {
                  r: 4,
                  magnet: true,
                  stroke: strokeColor,
                  strokeWidth: 1,
                  fill: '#fff',
                  style: {
                    visibility: 'hidden'
                  }
                }
              }
            },
            left: {
              position: 'left',
              attrs: {
                circle: {
                  r: 4,
                  magnet: true,
                  stroke: strokeColor,
                  strokeWidth: 1,
                  fill: '#fff',
                  style: {
                    visibility: 'hidden'
                  }
                }
              }
            }
          },
          items: [
            {
              group: 'right'
            },
            {
              group: 'left'
            }
          ]
        }
      }

      Graph.registerNode(
        'custom-rect-start',
        {
          inherit: 'rect',
          width: 86,
          height: 46,
          attrs: {
            body: {
              strokeWidth: 1,
              stroke: '#F8CA52',
              fill: '#FFFCF6'
            },
            text: {
              fontSize: 12,
              fill: '#262626'
            }
          },
          ports: {
            groups: {
              right: {
                position: 'right',
                attrs: {
                  circle: {
                    r: 4,
                    magnet: true,
                    stroke: '#F8CA52',
                    strokeWidth: 1,
                    fill: '#fff',
                    style: {
                      visibility: 'hidden'
                    }
                  }
                }
              }
            },
            items: [
              {
                group: 'right'
              }
            ]
          }
        },
        true
      )
      Graph.registerNode(
        'custom-rect-end',
        {
          inherit: 'rect',
          width: 86,
          height: 46,
          attrs: {
            body: {
              strokeWidth: 1,
              stroke: '#5C80F6',
              fill: '#F5F7FE'
            },
            text: {
              fontSize: 12,
              fill: '#262626'
            }
          },
          ports: {
            groups: {
              left: {
                position: 'left',
                attrs: {
                  circle: {
                    r: 4,
                    magnet: true,
                    stroke: '#5C80F6',
                    strokeWidth: 1,
                    fill: '#fff',
                    style: {
                      visibility: 'hidden'
                    }
                  }
                }
              }
            },
            items: [
              {
                group: 'left'
              }
            ]
          }
        },
        true
      )
      Graph.registerNode(
        'custom-rect',
        {
          inherit: 'rect',
          width: 86,
          height: 46,
          attrs: {
            text: {
              fontSize: 12,
              fill: '#262626'
            }
          }
        },
        true
      )

      // 基础流程图-group
      const r1 = this.graph.createNode({
        shape: 'custom-rect-start',
        attrs: {
          body: {
            rx: 6,
            ry: 6
          },
          data: {
            type: 'start',
            data: {}
          }
        },
        label: '开始'
      })

      const r2 = this.graph.createNode({
        shape: 'custom-rect-end',
        attrs: {
          body: {
            rx: 6,
            ry: 6
          },
          data: {
            type: 'end',
            data: {}
          }
        },
        label: '结束'
      })
      const r3 = this.graph.createNode({
        shape: 'custom-rect',
        attrs: {
          body: {
            strokeWidth: 1,
            stroke: '#7DD272',
            fill: '#F5FCF5',
            rx: 6,
            ry: 6
          },
          data: {
            type: 'supplicantServices',
            data: {}
          }
        },
        ports: { ...ports('#7DD272') },
        label: '请求方服务'
      })
      const r4 = this.graph.createNode({
        shape: 'custom-rect',
        attrs: {
          body: {
            strokeWidth: 1,
            stroke: '#7F4AF5',
            fill: '#F8F5FE',
            rx: 6,
            ry: 6
          },
          data: {
            type: 'providerServices',
            data: {}
          }
        },
        ports: { ...ports('#7F4AF5') },
        label: '提供方服务'
      })
      // const r5 = this.graph.createNode({
      //   shape: 'custom-rect',
      //   label: '协议转换'
      // })
      const r6 = this.graph.createNode({
        shape: 'custom-rect',
        attrs: {
          body: {
            strokeWidth: 1,
            stroke: '#5BBBF9',
            fill: '#F6FCFF',
            rx: 6,
            ry: 6
          },
          data: {
            type: 'dataMapping',
            data: {}
          }
        },
        ports: { ...ports('#5BBBF9') },
        label: '数据映射'
      })
      const r7 = this.graph.createNode({
        shape: 'custom-rect',
        attrs: {
          body: {
            strokeWidth: 1,
            stroke: '#EE6F45',
            fill: '#FEF7F5',
            rx: 6,
            ry: 6
          },
          data: {
            type: 'queueConfig',
            data: {}
          }
        },
        ports: { ...ports('#EE6F45') },
        label: '队列配置'
      })
      // const r8 = this.graph.createNode({
      //   shape: 'custom-rect',
      //   label: '加解密配置'
      // })
      stencil.load([r1, r4, r6, r7, r3, r2], 'group')
    }
  }
}
</script>

<style lang="scss" scoped>
::v-deep.service-adaptation {
  .custom-label {
    color: #1296DB;
    font-size: 16px;
  }
  .el-input-number .el-input__inner {
    text-align: left;
  }
}
</style>

<style lang="scss">
.service-adaptation {
  width: 100%;
  height: calc(100vh - 160px);
  padding: 16px;
  user-select:none;

  #container {
    height: 100%;
    overflow: hidden;

    &.is-disable {
      position: relative;
      &::after {
        content: '';
        position: absolute;
        top: 0;
        left: 0;
        bottom: 0;
        right: 0;
        background-color: rgba(0, 0, 0, 0.1);
        z-index: 1;
        cursor: not-allowed;
      }
    }
  }

  #stencil {
    width: 100%;
    height: 120px;
    position: relative;
  }

  #graph-container {
    width: 100%;
    height: calc(100% - 120px);
  }

  .x6-widget-stencil {
    background-color: #fff;
  }

  .x6-widget-stencil-title {
    background-color: #fff;
  }

  .x6-widget-stencil-group-title {
    background-color: #fff !important;
  }

  .x6-widget-transform {
    margin: -1px 0 0 -1px;
    padding: 0px;
    border: 1px solid #239edd;
  }

  .x6-widget-transform > div {
    border: 1px solid #239edd;
  }

  .x6-widget-transform > div:hover {
    background-color: #3dafe4;
  }

  .x6-widget-transform-active-handle {
    background-color: #3dafe4;
  }

  .x6-widget-transform-resize {
    border-radius: 0;
  }

  .x6-widget-selection-inner {
    border: 1px solid #239edd;
  }

  .x6-widget-selection-box {
    opacity: 0;
  }

  .service-adaptation-body {
    height: calc(100vh - 254px);
    display: flex;

    > .el-col {
      margin-top: 10px;
      height: 100%;
      &:nth-child(1) {
        min-width: 240px;
      }
      &:nth-child(2) {
        max-width: calc(100% - 240px);
      }
      .service-adaptation-body-left {
        height: 100%;
        padding: 10px;
        background: #fff;

        .el-tree {
          margin-top: 10px;
          height: calc(100% - 63px);
          overflow-y: auto;

          .el-tree-node__expand-icon {
            font-size: 18px;
          }

          .custom-tree-node {
            width: calc(100% - 30px);
            padding-right: 10px;
            display: flex;
            justify-content: space-between;
            align-items: center;

            > span:first-child {
              display: inline-block;
              width: calc(100% - 50px);
              overflow: hidden;
              white-space: nowrap;
              text-overflow: ellipsis;
              line-height: 40px;
            }

            .tree-btn i {
              font-size: 18px;
            }
          }
        }
      }
    }

    // 拖拽样式
    .left-col {
      position: relative;
      width: 300px;
      -ms-flex-negative: 0;
      flex-shrink: 0;
      margin-right: 8px;
    }
    .resize {
      cursor: col-resize;
      position: absolute;
      top: 45%;
      right: -9px;
      background-color: #d6d6d6;
      border-radius: 5px;
      margin-top: -10px;
      width: 10px;
      height: 50px;
      background-size: cover;
      background-position: 50%;
      font-size: 32px;
      color: #fff;
    }
    .right-col {
      width: calc(100% - 310px);
      height: 100%;
    }
  }

  .logs-dialog {
    .el-dialog__body {
      padding: 0 20px;
    }
  }

  // 删除按钮
  .text-del-btn {
    color: #EC638A;

    &.is-disabled {
      color: #C0C4CC;
    }
  }
}
</style>
